import Api, { checkFile } from '../upload.api'
import { useInfoStore } from '@/store'

const store = useInfoStore()
const baseUrl = import.meta.env.VITE_APP_BASE_API
const BREAK_FILE_URL = Api.file // 断点续传地址(用于大文件上传)

declare let WebUploader: any
let uploader: any

export const initWebUploader = (
  id: number | string,
  preocessCallBack: any,
  finishedUpload: any,
  checkFileError: any,
  startReal: any,
  changeFile: any
) => {
  const files: any = {}
  // 初始化上传控件
  const init = () => {
    beforeInit(finishedUpload)

    // 构建上传控件实例
    const config = configFun(id, preocessCallBack, finishedUpload, files)

    uploader = WebUploader.create(config)
    uploader.on('beforeFileQueued', (file: any) => {
      uploader.reset()
    })
    uploader.on('fileQueued', (file: any) => {
      changeFile(file)
      // config.fileQueued()
    })
    uploader.on('startUpload', (file: any) => {
      startReal(file)
    })
    uploader.on('uploadStart', (file: any) => {
      config.uploadStart(file)
    })
    uploader.on('uploadBeforeSend', (object: any, data: any) => {
      config.uploadBeforeSend(object, data)
    })
    uploader.on('uploadProgress', (file: any, percentage: number) => {
      config.uploadProgress(file, percentage)
    })
    uploader.on('uploadError', (file: any) => {
      config.uploadError(file)
    })
    uploader.on('uploadSuccess', (file: any) => {
      config.uploadSuccess(file)
    })
    uploader.on('error', (type: string) => {
      config.error(type)
      checkFileError(type)
    })
  }

  init()
  return uploader
}

const beforeInit = (finishedUpload: any) => {
  // 这个必须要写在实例化前面
  WebUploader.Uploader.unRegister('my-uploader')
  WebUploader.Uploader.register(
    {
      'before-send-file': 'beforeSendFile',
      'before-send': 'beforeSend',
      name: 'my-uploader'
    },
    {
      // 时间点1：所有分块进行上传之前调用此函数
      beforeSendFile: (file: any) => {
        const deferred = WebUploader.Deferred()
        new WebUploader.Uploader()
          .md5File(file, 0, 5242880)
          .then((val: string) => {
            file.md5 = val
            file.uid = WebUploader.Base.guid()
            // 进行md5判断
            void checkFile({
              fileName: file.name,
              md5: file.md5
            }).then((res: any) => {
              const data = JSON.parse(res)
              const status = data.errorCode
              deferred.resolve()
              switch (status) {
                case 0:
                  finishedUpload(file, 1)
                  // 忽略上传过程，直接标识上传成功；
                  uploader.skipFile(file)
                  file.pass = true
                  // fileUploaded(file)
                  break
                case 16:
                  // 部分已经上传到服务器了，但是差几个模块。
                  file.missChunks = data.data
                  break
                default:
                  break
              }
            })
          })
        return deferred.promise()
      },
      // 时间点2：如果有分块上传，则每个分块上传之前调用此函数
      beforeSend: (block: any) => {
        const deferred = WebUploader.Deferred()
        // 当前未上传分块
        const missChunks = block.file.missChunks
        // 当前分块
        const blockChunk = block.chunk
        if (
          missChunks !== null &&
          missChunks !== undefined &&
          missChunks !== ''
        ) {
          let flag = true
          for (let i = 0; i < missChunks.length; i++) {
            if (blockChunk === parseInt(missChunks[i])) {
              // 存在还未上传的分块
              flag = false
              break
            }
          }
          if (flag) {
            deferred.reject()
          } else {
            deferred.resolve()
          }
        } else {
          deferred.resolve()
        }
        return deferred.promise()
      }
    }
  )
}
const configFun = (
  id: number | string,
  preocessCallBack: any,
  finishedUpload: any,
  files: any
) => {
  return {
    // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
    server: `${baseUrl}${BREAK_FILE_URL}`,
    dnd: undefined,
    disableGlobalDnd: false,
    paste: document.body,
    pick: {
      id: `#${id}`,
      multiple: true
    },
    accept: {
      extensions: 'zip,7z',
      mimeTypes: '.zip,.7z'
    },
    thumb: {
      width: 300,
      height: 300,
      quality: 70,
      allowMagnify: false,
      crop: true,
      type: undefined
    },
    compress: {
      width: 1600,
      height: 1600,
      quality: 90,
      allowMagnify: false,
      crop: false,
      preserveHeaders: true,
      noCompressIfLarger: false,
      compressSize: 1048576
    },
    auto: false,
    runtimeOrder: 'html5,flash',
    prepareNextFile: true,
    chunked: true,
    chunkSize: 5242880,
    chunkRetry: 2,
    threads: 3,
    formData: {},
    fileVal: 'file',
    method: 'POST',
    sendAsBinary: false,
    fileNumLimit: 1,
    fileSizeLimit: undefined,
    fileSingleSizeLimit: 15 * 1024 * 1024 * 1024, // 15G
    duplicate: false,
    disableWidgets: undefined,
    headers: {
      Authorization: `Bearer ${store.token}`
    },
    beforeInit,
    // 文件队列
    fileQueued: (file: any) => {
      // uploader.upload()
    },
    // 上传文件之前先计算文件的MD5和ID
    uploadBeforeSend: (object: any, data: any) => {
      const file = object.file
      // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
      data.md5 = file.md5 || ''
      data.uid = file.uid
    },
    uploadStart: (file: any) => {
      // 上一次上传的时间节点、上一次已经上传大小(单位字节)、历史上传速率、平均速率
      files[file.id] = {
        startUploadTime: Date.now(),
        fileUploadedSize: 0
      }
    },
    // 上传进度更新
    uploadProgress: (file: any, percentage: number) => {
      // 计算当前上传速率，分别计算出时间差(以秒为单位)、该时间差内上传的文件大小(以字节为单位)
      const timeSpan = (Date.now() - files[file.id].startUploadTime) / 1000
      const fileDifference =
        file.size * percentage - files[file.id].fileUploadedSize
      // 用 文件差 / 时间差 = 单位 b/s
      const uploadRate = fileDifference / timeSpan

      if (file.uploadRate === undefined) {
        file.uploadRate = 0
      }

      // 每 秒 更新一次
      if (timeSpan >= 1) {
        // 重置上传时间
        files[file.id].startUploadTime = new Date().getTime()
        files[file.id].fileUploadedSize = file.size * percentage
        // 上传速率(b/s)
        file.uploadRate = Math.max(uploadRate, 0)
      }
      preocessCallBack(percentage)
    },
    uploadError: (file: any) => {
      // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
      console.error(`${file.id}上传出错`)
    },
    error: (type: string) => {
      if (type === 'Q_EXCEED_NUM_LIMIT') {
        console.error('文件数量超出限制')
      } else if (type === 'Q_TYPE_DENIED') {
        console.error('文件类型不满足条件')
      } else if (type === 'Q_EXCEED_SIZE_LIMIT') {
        console.error('文件总大小超出限制')
      } else if (type === 'F_DUPLICATE') {
        console.error('请勿重复添加')
      } else if (type === 'F_EXCEED_SIZE') {
        console.error('文件过大')
      } else {
        console.error(type)
      }
    },
    // 上传完成后执行
    uploadSuccess: (file: any) => {
      finishedUpload(file)
    }
  }
}
